---
type: tutorial
title: 태그 색인 페이지 구축
description: |-
  튜토리얼: 첫 번째 Astro 블로그 구축 — 지금까지 배운 모든 것을 사용하여 태그 인덱스 페이지 구축
i18nReady: true
---

import Box from '~/components/tutorial/Box.astro';
import Checklist from '~/components/Checklist.astro';
import MultipleChoice from '~/components/tutorial/MultipleChoice.astro';
import Option from '~/components/tutorial/Option.astro';
import PreCheck from '~/components/tutorial/PreCheck.astro';
import { Steps } from '@astrojs/starlight/components';

이제 모든 태그에 대한 개별 페이지가 있으므로 해당 페이지에 대한 링크를 만들 차례입니다.

<PreCheck>
  - `/pages/folder/index.astro` 라우팅 패턴을 사용하여 새 페이지 추가
  - 각 태그 페이지에 연결되는 모든 고유 태그 목록을 표시
  - 새로운 태그 페이지에 대한 탐색 링크로 사이트 업데이트
</PreCheck>

## `/pages/folder/index.astro` 라우팅 패턴 사용

웹사이트에 태그 인덱스 페이지를 추가하려면 `src/pages/tags.astro`에 새 파일을 생성하면 됩니다.

그러나 이미 `/tags/` 디렉터리가 있으므로 Astro의 다른 라우팅 패턴을 활용하고 태그와 관련된 모든 파일을 함께 보관할 수 있습니다.

<Box icon="puzzle-piece">

## 직접 시도해 보기 - 태그 색인 페이지 만들기

<Steps>
1. `src/pages/tags/` 디렉터리에 `index.astro`라는 새 파일을 생성합니다.

2. `http://localhost:4321/tags`로 이동하여 사이트에 이 URL의 페이지가 포함되어 있는지 확인하세요. 비어 있지만 존재할 것입니다.

3. 레이아웃을 사용하는 `src/pages/tags/index.astro`에 최소 페이지를 만듭니다. 여러분은 전에 이 작업을 한 적이 있습니다!

    <details>
      <summary>확장하여 단계를 확인하세요.</summary>
      <Steps>
      1. `src/pages/tags/`에 새 페이지 컴포넌트를 만듭니다.

          <details>
          <summary>파일 이름 표시</summary>
          ```
          index.astro
          ```
          </details>

      2. `<BaseLayout>`을 가져와 사용하세요.

          <details>
          <summary>Show the code</summary>
          ```astro title=" src/pages/tags/index.astro"
          ---
          import BaseLayout from '../../layouts/BaseLayout.astro';
          ---
          <BaseLayout></BaseLayout>
          ```
          </details>

      3. 페이지 제목을 정의하고 이를 컴포넌트 속성으로 레이아웃에 전달합니다.

          <details>
          <summary>Show the code</summary>
          ```astro title="src/pages/tags/index.astro" ins={3} "pageTitle"
          ---
          import BaseLayout from '../../layouts/BaseLayout.astro';
          const pageTitle = "Tag Index";
          ---
          <BaseLayout pageTitle={pageTitle}></BaseLayout>
          ```
          </details>
      </Steps>
    </details>

4. 브라우저 미리보기를 다시 확인하면 콘텐츠를 추가할 준비가 된 형식화된 페이지가 있을 것입니다!
</Steps>
</Box>

## 태그 배열 생성

이전에 `map()`을 사용하여 배열의 목록에 항목을 표시했습니다. 모든 태그의 배열을 정의한 다음 이 페이지의 목록에 표시하는 것은 어떤 모습일까요?

<details>
    <summary>코드 보기</summary>
    
    ```astro title="src/pages/tags/index.astro"
    ---
    import BaseLayout from '../../layouts/BaseLayout.astro';    
    const tags = ['astro', 'blogging', 'learning in public', 'successes', 'setbacks', 'community']
    const pageTitle = "Tag Index";
    ---
    <BaseLayout pageTitle={pageTitle}>
      <ul>
        {tags.map((tag) => <li>{tag}</li>)}
      </ul>
    </BaseLayout>
    ```
</details>

이렇게 할 수도 있지만 이후 블로그 게시물에서 새 태그를 사용할 때마다 이 파일로 돌아와서 배열을 업데이트해야 합니다.

다행히도 한 줄의 코드로 모든 Markdown 파일의 데이터를 가져온 다음 모든 태그 목록을 반환하는 방법을 이미 알고 있습니다.

<Steps>

1. `src/pages/tags/index.astro`에서 모든 `.md` 블로그 게시물 파일의 데이터에 대한 페이지 액세스를 제공하는 프런트매터 스크립트에 코드 줄을 추가합니다.

    <details>
    <summary>코드 보기</summary>
    ```astro title = "src/pages/tags/index.astro" ins={3}
    ---
    import BaseLayout from '../../layouts/BaseLayout.astro';
    const allPosts = Object.values(import.meta.glob('../posts/*.md', { eager: true }));
    const pageTitle = "Tag Index";
    ---
    ```
    </details>

2. 그런 다음 페이지 컴포넌트에 다음 JavaScript 줄을 추가합니다. 이는 고유한 태그 목록을 반환하기 위해 `src/pages/tags/[tag].astro`에서 사용한 Astro의 내장 TypeScript 지원을 활용한 동일한 코드입니다.

    ```astro title = "src/pages/tags/index.astro" ins={4}
    ---
    import BaseLayout from '../../layouts/BaseLayout.astro';
    const allPosts = Object.values(import.meta.glob('../posts/*.md', { eager: true }));
    const tags = [...new Set(allPosts.map((post: any) => post.frontmatter.tags).flat())];
    const pageTitle = "Tag Index";
    ---
    
    ```
</Steps>

## 태그 목록 만들기

이번에는 순서가 지정되지 않은 목록에 항목을 만드는 대신 `<div>` 안에 각 항목에 대해 하나의 `<p>`를 만듭니다. 패턴이 익숙해 보일 것입니다!

<Steps>
1. 컴포넌트 템플릿에 다음 코드를 추가합니다.

    ```astro title="src/pages/tags/index.astro" ins={2}
    <BaseLayout pageTitle={pageTitle}>
      <div>{tags.map((tag) => <p>{tag}</p>)}</div>
    </BaseLayout>
    ```
    브라우저 미리보기에서 나열된 태그를 볼 수 있는지 확인하세요.

2. 각 태그 링크를 자체 페이지로 만들려면 각 태그 이름에 다음 `<a>` 링크를 추가하세요. Astro의 내장 TypeScript 지원을 통해 블로그 게시물에 태그가 없거나 형식이 잘못된 경우 오류를 표시하여 코드를 확인하고 수정할 수 있습니다.

    ```astro title="src/pages/tags/index.astro" '/tags/${tag}'
    <BaseLayout pageTitle={pageTitle}>
      <div>
        {tags.map((tag) => (
          <p><a href={`/tags/${tag}`}>{tag}</a></p>
        ))}
      </div>
    </BaseLayout>
    ```
</Steps>

## 태그 목록에 스타일 추가

<Steps>
1. 다음 CSS 클래스를 추가하여 `<div>`와 생성될 각 `<p>`의 스타일을 지정하세요. 참고: Astro는 클래스 이름을 추가하기 위해 HTML 구문을 사용합니다!

    ```astro title="src/pages/tags/index.astro" 'class="tags"' 'class="tag"'
    <BaseLayout pageTitle={pageTitle}>
    <div class="tags">
      {tags.map((tag) => (
        <p class="tag"><a href={`/tags/${tag}`}>{tag}</a></p>
      ))}
    </div>
    </BaseLayout>
    ```

2. 이 페이지에 다음 `<style>` 태그를 추가하여 새로운 CSS 클래스를 정의하세요.

    ```astro title="src/pages/tags/index.astro"
    <style>
      a {
        color: #00539F;
      }

      .tags {
        display: flex; 
        flex-wrap: wrap; 
      }

      .tag {
        margin: 0.25em;
        border: dotted 1px #a1a1a1;
        border-radius: .5em;
        padding: .5em 1em;
        font-size: 1.15em;
        background-color: #F8FCFD;
      }
    </style>
    ```

3. `http://localhost:4321/tags`에서 브라우저 미리보기를 확인하여 새로운 스타일이 있는지, 페이지의 각 태그에 자체 개별 태그 페이지에 대한 작동하는 링크가 있는지 확인하세요.
</Steps>

### 코드 체크인

새 페이지는 다음과 같습니다.

```astro title="src/pages/tags/index.astro"
--- 
import BaseLayout from '../../layouts/BaseLayout.astro';
const allPosts = Object.values(import.meta.glob('../posts/*.md', { eager: true }));
const tags = [...new Set(allPosts.map((post: any) => post.frontmatter.tags).flat())];
const pageTitle = "Tag Index";
---
<BaseLayout pageTitle={pageTitle}>
  <div class="tags">
    {tags.map((tag) => (
      <p class="tag"><a href={`/tags/${tag}`}>{tag}</a></p>
    ))}
  </div>
</BaseLayout>
<style>
  a {
    color: #00539F;
  }

  .tags {
    display: flex; 
    flex-wrap: wrap; 
  }

  .tag {
    margin: 0.25em;
    border: dotted 1px #a1a1a1;
    border-radius: .5em;
    padding: .5em 1em;
    font-size: 1.15em;
    background-color: #F8FCFD;
  }
</style>
```

## 이 페이지를 탐색에 추가

지금은 `http://localhost:4321/tags`로 이동하여 이 페이지를 볼 수 있습니다. 이 페이지에서 개별 태그 페이지에 대한 링크를 클릭할 수 있습니다.

하지만 여전히 웹사이트의 다른 페이지에서 이러한 페이지를 검색할 수 있도록 해야 합니다.

<Steps>
1. `Navigation.astro` 컴포넌트에 이 새 태그 인덱스 페이지에 대한 링크를 포함합니다.

    <details>
    <summary>Show me the code</summary>
    ```astro title="src/components/Navigation.astro" ins={4}
    <a href="/">Home</a>
    <a href="/about/">About</a>
    <a href="/blog/">Blog</a>
    <a href="/tags/">Tags</a>
    ```
    </details>
</Steps>

<Box icon="puzzle-piece">

## 과제: 블로그 게시물 레이아웃에 태그 포함

이제 각 블로그 게시물에 태그 목록을 표시하고 태그 페이지에 연결하는 데 필요한 모든 코드를 작성했습니다. 재사용할 수 있는 기존 작업이 있습니다!

아래 단계를 수행한 후 [최종 코드 샘플](#코드-체크인-markdownpostlayout)과 비교하여 작업 내용을 확인하세요.

<Steps>

1. `src/pages/tags/index.astro`에서 `<div class="tags">...</div>` 및 `<style>...</style>`을 복사하여 `MarkdownPostLayout.astro` 내부에서 재사용하세요.

    ```astro title="src/layouts/MarkdownPostLayout.astro" ins={11-15, 19-37}
    ---
    import BaseLayout from './BaseLayout.astro';
    const { frontmatter } = Astro.props;
    --- 
    <BaseLayout pageTitle={frontmatter.title}>
      <p><em>{frontmatter.description}</em></p>
      <p>{frontmatter.pubDate.toString().slice(0,10)}</p>
      <p><em>{frontmatter.description}</em></p>
      <p>Written by: {frontmatter.author}</p>
      <img src={frontmatter.image.url} width="300" alt={frontmatter.image.alt} /> 

      <div class="tags">
        {tags.map((tag: string) => (
        <p class="tag"><a href={`/tags/${tag}`}>{tag}</a></p>
        ))}
      </div>

      <slot />
    </BaseLayout>
    <style>
      a {
        color: #00539F;
      }

      .tags {
        display: flex; 
        flex-wrap: wrap; 
      }

      .tag {
        margin: 0.25em;
        border: dotted 1px #a1a1a1;
        border-radius: .5em;
        padding: .5em 1em;
        font-size: 1.15em;
        background-color: #F8FCFD;
      }
    </style>
    ```

</Steps>

이 코드가 작동하려면 `MarkdownPostLayout.astro`에 붙여넣은 코드를 **한 번만 수정**해야 합니다. 그것이 무엇인지 알아낼 수 있나요?

<details>
<summary>힌트 보기</summary>

레이아웃 템플릿에 다른 props (예: title, author, 등)는 어떻게 작성되어 있나요? 레이아웃은 개별 블로그 게시물에서 props를 어떻게 받나요?
</details>

<details>
<summary>또 다른 힌트 보기!</summary>

태그와 같이 레이아웃에서 `.md` 블로그 게시물의 props (전달된 값)를 사용하려면 값 앞에 특정 단어를 붙여야 합니다.

<details>
<summary>코드 보기!</summary>

```astro title="src/layouts/MarkdownPostLayout.astro" "frontmatter"
    <div class="tags">
      {frontmatter.tags.map((tag: string) => (
        <p class="tag"><a href={`/tags/${tag}`}>{tag}</a></p>
      ))}
    </div>
```
</details>
</details>

</Box>

### 코드 체크인: MarkdownPostLayout

작업을 확인하거나 `MarkdownPostLayout.astro`에 복사할 완전하고 올바른 코드를 원하는 경우 Astro 컴포넌트는 다음과 같습니다.

```astro title="src/layouts/MarkdownPostLayout.astro"
---
import BaseLayout from './BaseLayout.astro';
const { frontmatter } = Astro.props;
--- 
<BaseLayout pageTitle={frontmatter.title}>
  <p><em>{frontmatter.description}</em></p>
  <p>{frontmatter.pubDate.toString().slice(0,10)}</p>

  <p>Written by: {frontmatter.author}</p>

  <img src={frontmatter.image.url} width="300" alt={frontmatter.image.alt} /> 

  <div class="tags">
    {frontmatter.tags.map((tag: string) => (
      <p class="tag"><a href={`/tags/${tag}`}>{tag}</a></p>
    ))}
  </div>

  <slot />
</BaseLayout>
<style>
  a {
    color: #00539F;
  }

  .tags {
    display: flex; 
    flex-wrap: wrap; 
  }

  .tag {
    margin: 0.25em;
    border: dotted 1px #a1a1a1;
    border-radius: .5em;
    padding: .5em 1em;
    font-size: 1.15em;
    background-color: #F8FCFD;
  }
</style>
```

<Box icon="question-mark">

### 지식을 테스트해보세요

각 파일 경로를 동일한 경로에 페이지를 생성할 두 번째 파일 경로와 일치시키세요.

1. `src/pages/categories.astro`

    <MultipleChoice>
      <Option>`src/pages/posts/post.astro`</Option>
      <Option>`src/pages/posts/index.astro`</Option>
      <Option>`src/components/shoes/Shoe.astro`</Option>
      <Option isCorrect>`src/pages/categories/index.astro`</Option>
    </MultipleChoice>

2. `src/pages/posts.astro`

    <MultipleChoice>
      <Option>`src/pages/products/shoes.astro`</Option>
      <Option>`src/pages/posts/post.astro`</Option>
      <Option isCorrect>`src/pages/posts/index.astro`</Option>
      <Option>`src/pages/categories/index.astro`</Option>
    </MultipleChoice>

3. `src/pages/products/shoes/index.astro`

    <MultipleChoice>
      <Option isCorrect>`src/pages/products/shoes.astro`</Option>
      <Option>`src/pages/posts/post.astro`</Option>
      <Option>`src/pages/posts/index.astro`</Option>
      <Option>`src/components/shoes/Shoe.astro`</Option>
    </MultipleChoice>

</Box>

<Box icon="check-list">

## 체크리스트

<Checklist>
- [ ] Astro의 `/pages/folder/index.astro` 라우팅 기능을 사용할 수 있습니다.
</Checklist>
</Box>

### Resources

- [Astro의 정적 라우팅](/ko/guides/routing/#정적-라우트)
